import datetime

from fastapi import APIRouter
from re_common.baselibrary.utils.basedict import BaseDicts
from re_common.baselibrary.utils.core.mlamada import bools_string
from re_common.baselibrary.utils.core.requests_core import MsgCode

from apps.allsubdb.globalapi.models import SaveStepLogMongoModel, SaveStepInfoMongoModel, VerifyRuleModel, \
    UseRule, ProcessModel, UpInInfoModel, UpInLogModel, UpInRuleModel
from apps.core.global_model import IdModel
from apps.core.m_route import ContextIncludedRoute
from apps.core.return_info import ReturnInfo, InputInfoModel, SUCCESS, FAILED
from apps.sql_app.mmongodb import MongoDBClient

router = APIRouter(route_class=ContextIncludedRoute)


@router.post("/process/select_step_info")
async def select_step_info(input: InputInfoModel[ProcessModel]):
    """
    查询step_info表的数据,提供通过id和条件查询
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    mongoInfo = MongoDBClient.db30_1.client.htmljson.process_step_info
    qurey_dicts = input.data.dict(by_alias=True)
    qurey_dicts = BaseDicts.removeDictsAllNone(qurey_dicts)
    info = await mongoInfo.find_one(qurey_dicts)
    if info:
        return_info.data = info
    else:
        return_info.data = {}
    return_info.status = SUCCESS
    return_info.msg_code = 200
    return return_info.todict()


@router.post("/process/insert_update_step_info")
async def up_in_step_info(input: InputInfoModel[UpInInfoModel]):
    """
    插入或者更新某张表
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    mongoInfo = MongoDBClient.db30_1.client.htmljson.process_step_info
    qurey_dicts = input.data.query.dict(by_alias=True)
    qurey_dicts = BaseDicts.removeDictsAllNone(qurey_dicts)
    info = await mongoInfo.find_one(qurey_dicts)
    if info:
        update_dicts = input.data.update.dict()
        update_dicts = BaseDicts.removeDictsAllNone(update_dicts)
        for k, v in update_dicts.items():
            if isinstance(v, dict):
                info[k].update(v)
            else:
                info[k] = v
        info["update_time"] = str(datetime.datetime.now())

        result = await mongoInfo.replace_one({'_id': info["_id"]}, info)
        return_info.data = info
    else:
        task_name = input.data.query.task_name
        types = input.data.query.types
        tags = input.data.query.tags
        if task_name and types and tags:
            sinfo_ids = "_".join([task_name, types, tags, datetime.datetime.now().strftime('%Y%m%d%H%M%S')])
            stepinfo = {}
            stepinfo["_id"] = sinfo_ids
            stepinfo["task_name"] = task_name
            stepinfo["types"] = types
            stepinfo["tags"] = tags
            stepinfo["step_info"] = input.data.update.step_info
            stepinfo["stat"] = input.data.update.stat
            stepinfo["update_time"] = str(datetime.datetime.now())
            stepinfo["create_time"] = str(datetime.datetime.now())
            mmObj = SaveStepInfoMongoModel.parse_obj(stepinfo)
            result = await mongoInfo.insert_one(mmObj.dict(by_alias=True))
            return_info.data = mmObj.dict(by_alias=True)
        else:
            return_info.status = FAILED
            return_info.msg_code = 200
            return_info.msg = "插入数据，但 task_name, types, tags存在None，请检查"
            return_info.data = input.dict()
            return return_info.todict()

    return_info.status = SUCCESS
    return_info.msg_code = 200
    return return_info.todict()


@router.post("/process/select_step_log")
async def select_step_info(input: InputInfoModel[ProcessModel]):
    """
    查询step_info表的数据,提供通过id和条件查询
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    mongoInfo = MongoDBClient.db30_1.client.htmljson.process_step_log
    qurey_dicts = input.data.dict(by_alias=True)
    qurey_dicts = BaseDicts.removeDictsAllNone(qurey_dicts)
    info = await mongoInfo.find_one(qurey_dicts)
    if info:
        return_info.data = info
    else:
        return_info.data = {}
    return_info.status = SUCCESS
    return_info.msg_code = 200
    return return_info.todict()


@router.post("/process/insert_update_step_log")
async def up_in_step_log(input: InputInfoModel[UpInLogModel]):
    """
    插入或者更新某张表
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    mongoLog = MongoDBClient.db30_1.client.htmljson.process_step_log

    qurey_dicts = input.data.query.dict()
    # 去除查询条件的空值
    qurey_dicts = BaseDicts.removeDictsAllNone(qurey_dicts)
    log = await mongoLog.find_one(qurey_dicts)
    # 结果data结构
    data = {"new_id": "", "log_info": ""}
    # 如果有值
    if log:
        # 取出各个值
        steplog = input.data.update
        stat = steplog.stat
        ids = steplog.log_info.id
        client_data = steplog.log_info.client_data
        is_all_client = steplog.log_info.is_all_client
        rule_data = steplog.log_info.rule_data
        is_all_rule = steplog.log_info.is_all_rule
        log["stat"] = stat
        # 如果该条数据不存在
        if ids == "":
            ids = str(datetime.datetime.now())
            data["new_id"] = ids
            dicts = {}
            dicts["id"] = ids
            dicts["client_data"] = client_data
            dicts["rule_data"] = rule_data
            log["log_info"].append(dicts)
        # 如果该条数据存在
        else:
            is_have = False
            for items in log["log_info"]:
                # 找到列表中id对应的值
                if items["id"] == ids:
                    data["new_id"] = ids
                    # 如果为true 全部替换
                    if is_all_client == "true":
                        items["client_data"] = client_data
                    else:
                        items["client_data"].update(client_data)

                    if is_all_rule == "true":
                        items["rule_data"] = rule_data
                    else:
                        items["rule_data"].update(rule_data)
                    is_have = True
            if not is_have:
                return_info.status = FAILED
                return_info.msg_code = 200
                return_info.msg = "没有对应id的数据请检查输入数据是否正常"
                return_info.data = input.dict()
                return return_info.todict()
        log["update_time"] = str(datetime.datetime.now())
        result = await mongoLog.replace_one({'_id': log["_id"]}, log)
        data["log_info"] = log
        return_info.data = data
    else:
        task_name = input.data.query.task_name
        types = input.data.query.types
        tags = input.data.query.tags
        step_name = input.data.query.step_name
        if task_name and types and tags and step_name:
            slog_ids = "_".join([task_name, types, tags, step_name, datetime.datetime.now().strftime('%Y%m%d%H%M%S')])
            stat = input.data.update.stat
            update_time = str(datetime.datetime.now())
            create_time = str(datetime.datetime.now())
            dicts = input.data.update.log_info.dict()
            new_id = str(datetime.datetime.now())
            dicts["id"] = new_id
            log_info = [dicts]
            mmObj = SaveStepLogMongoModel(
                _id=slog_ids, task_name=task_name, types=types,
                tags=tags, step_name=step_name, stat=stat,
                log_info=log_info, update_time=update_time,
                create_time=create_time)
            result = await mongoLog.insert_one(mmObj.dict(by_alias=True))
            data["log_info"] = mmObj.dict(by_alias=True)

            data["new_id"] = new_id
            return_info.data = data

        else:
            return_info.status = FAILED
            return_info.msg_code = 200
            return_info.msg = "插入数据，但 task_name, types, tags,step_name存在None，请检查"
            return_info.data = input.dict()
            return return_info.todict()

    return_info.status = SUCCESS
    return_info.msg_code = 200
    return return_info.todict()


@router.post("/process/select_step_rule")
async def select_step_info(input: InputInfoModel[ProcessModel]):
    """
    查询step_info表的数据,提供通过id和条件查询
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    mongoInfo = MongoDBClient.db30_1.client.htmljson.process_step_rule
    qurey_dicts = input.data.dict(by_alias=True)
    qurey_dicts = BaseDicts.removeDictsAllNone(qurey_dicts)

    if not qurey_dicts:
        return_info.status = FAILED
        return_info.msg_code = MsgCode.MONGO_NO_ID
        return return_info.todict()
    info = await mongoInfo.find_one(qurey_dicts)
    if info:
        return_info.data = info
    else:
        return_info.data = {}
    return_info.status = SUCCESS
    return_info.msg_code = 200
    return return_info.todict()


@router.post("/process/insert_update_step_rule")
async def up_in_step_log(input: InputInfoModel[UpInRuleModel]):
    """
    插入或者更新某张表
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    mongo_rule = MongoDBClient.db30_1.client.htmljson.process_step_rule

    qurey_dicts = input.data.query.dict()
    qurey_dicts = BaseDicts.removeDictsAllNone(qurey_dicts)
    log = await mongo_rule.find_one(qurey_dicts)
    if log:
        update_dicts = input.data.update.dict()
        update_dicts = BaseDicts.removeDictsAllNone(update_dicts)
        for k, v in update_dicts.items():
            if isinstance(v, list):
                for item1 in v:
                    key1 = item1["key"]
                    for item in log[k]:
                        if item["key"] == key1:
                            log[k].remove(item)
                log[k].extend(v)
            else:
                log[k] = v
        log["update_time"] = str(datetime.datetime.now())

        result = await mongo_rule.replace_one({'_id': log._id}, log)
        return_info.data = log
    else:
        task_name = input.data.query.task_name
        types = input.data.query.types
        tags = input.data.query.tags
        step_name = input.data.query.step_name
        if task_name and types and tags and step_name:
            rule_ids = "_".join([task_name, types, tags, step_name])
            retry = input.data.update.retry
            keys = input.data.update.keys
            is_skip = input.data.update.is_skip
            vrm_model = VerifyRuleModel(_id=rule_ids, task_name=task_name, types=types,
                                        step_name=step_name, tags=tags, retry=retry,
                                        keys=keys, is_skip=is_skip,
                                        update_time=str(datetime.datetime.now()),
                                        create_time=str(datetime.datetime.now()))
            result = await mongo_rule.insert_one(vrm_model.dict(by_alias=True))

        else:
            return_info.status = FAILED
            return_info.msg_code = 200
            return_info.msg = "插入数据，但 task_name, types, tags,step_name存在None，请检查"
            return_info.data = input.dict()
            return return_info.todict()

    return_info.status = SUCCESS
    return_info.msg_code = 200
    return return_info.todict()


@router.post("/process/use_rule")
async def use_rule(input: InputInfoModel[UseRule]):
    return_info = ReturnInfo()
    data_log = input.data.data_log
    list_rule = input.data.rule_list
    result_dicts = {}
    result_dicts["not_have"] = []
    result_dicts["rule_list"] = []
    result_stat = True
    for item in list_rule:
        key = item.key
        if key not in data_log:
            result_dicts["not_have"].append(key)
            result_stat = False
        else:
            data = str(data_log[key])
            rule = item.rule
            value = item.value
            bools = eval(data + rule + value)
            if not bools:
                result_dicts["rule_list"].append(key + ":" + data + rule + value)
                result_stat = False
    return_info.status = SUCCESS
    return_info.msg = "验证" + bools_string(result_stat)
    result_dicts.update({"result_stat": bools_string(result_stat)})
    return_info.data = result_dicts
    return return_info.todict()


@router.post("/process/select_info_end")
async def select_info_end(input: InputInfoModel[IdModel]):
    """
    查看是否全部状态结束
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    info_id = input.data.id
    mongoInfo = MongoDBClient.db30_1.client.htmljson.process_step_info
    mongoLog = MongoDBClient.db30_1.client.htmljson.process_step_log
    info = await mongoInfo.find_one({"_id": info_id})
    if info:
        lists = []
        for k, v in info["step_info"].items():
            log = await mongoLog.find_one({"_id": v})
            if not log:
                return_info.status = FAILED
                return_info.msg = "info 中记录的log不存在,请检查数据库"
                return_info.data = k + ";" + v
                return return_info.todict()
            lists.append({"key": k, "value": v, "stat": log["stat"]})
        return_info.data = lists
        return_info.msg = "获取所有状态成功"
        return_info.status = SUCCESS
        return return_info.todict()
    else:
        return_info.status = FAILED
        return_info.msg = "info id 错误"
        return_info.data = ""
        return return_info.todict()
